///* !!! Doost !!! */
//
///*
//   A Java implementation of BLAKE2B cryptographic digest algorithm.
//
//   Joubin Mohammad Houshyar <alphazero@sensesay.net>
//   bushwick, nyc
//   02-14-2014
//
//   --
//
//   To the extent possible under law, the author(s) have dedicated all copyright
//   and related and neighboring rights to this software to the public domain
//   worldwide. This software is distributed without any warranty.
//
//   You should have received a copy of the CC0 Public Domain Dedication along with
//   this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//*/
//
//package ove.crypto.digest;
//
//import java.security.MessageDigest;
//import java.util.concurrent.TimeUnit;
//
//import ove.alphazero.util.CmdLineArgs;
//
///**
// * REVU: let's keep the jar minimal. move to a child project.
// * @author  start
// */
//public class Bench implements Runnable {
//
//	interface Default {
//		int WARMUP = 3; // seconds
//		String DIGEST = "blake2b-512";
//	}
//
//	static volatile boolean f_run = true;
//
//	static class Usage {
//		private static void explain (final String opt, final String optfmt, Object ... args) {
//			final String fmtstr = String.format("%3s\t%s\n", opt, optfmt);
//			System.out.format(fmtstr, args);
//		}
//		static int usage () {
//			System.out.println("usage: java -cp .. ove.crypto.digest.Bench [options]");
//			System.out.println("[options]");
//			explain ("-d",  "digest algorithm to bench - one of " +
//					"{blake2-256, blake2-256, sha1, sha-256, sha-512, md5}. default: %s", Default.DIGEST);
//			explain ("-w",  "warm-up delay in seconds. default: %d seconds", Default.WARMUP);
//
//			return -1;
//		}
//	}
//
//	public static void main(final String... args) {
//		final CmdLineArgs clargs = CmdLineArgs.parse(null, args);
//		if (clargs.isUsage()) {
//			System.exit(Usage.usage());
//		}
//		try {
//			String algorithm = clargs.getOption("d", Default.DIGEST);
//			int warmup = clargs.getIntOption("w", Default.WARMUP);
//
//			final Bench bench = new Bench (algorithm, warmup);
//			final Thread brth = new Thread(bench, "bench-runner");
//			brth.start();
//			System.in.read();
//			f_run = false;
//			brth.join();
//
//		} catch (Throwable e) {
//			System.exit(Usage.usage());
//		}
//	}
//
//	private final String algorithm;
//	private final int warmup;
//	private final Call call;
//
//	Bench (final String algorithm, final int warmup) {
//		this.algorithm = algorithm;
//		this.warmup = warmup;
//		this.call = getBenchedCall();
//	}
//
//	private Call getBenchedCall() {
//
//		Call call = null;
//		if ("blake2b-512".equalsIgnoreCase(algorithm)) {
//			call = newCallBlake2b(64);
//		} else if ("blake2b-256".equalsIgnoreCase(algorithm)) {
//			call = newCallBlake2b(32);
//		} else {
//			call = newCallJceAlgorithm(algorithm);
//		}
//		return call;
//	}
//	private static final void puts(final String s) {
//		System.out.format("%s\n", s);
//	}
//	@Override public void run () {
//
//		System.out.printf("warming up ...");
//		final long t0 = System.currentTimeMillis();
//		byte[] b0 = new byte[5000];
//		while (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - t0) < warmup) {
//			call.func(b0);
//		}
//		System.out.printf("\r");
//		b0 = null;
//		System.gc();
//
//		puts ("Bench - hit any key to stop. (use -h to list options)");
//		puts ("");
//		puts ("digest       | iterations | size (B/iter) | dt (nsec/iter) | throughput (MB/sec)");
//
//		int size = 64;
//		int maxruns = 20;
//
//		while(size < 1 << 23) {
//			final double[] throughputs = new double[maxruns];
//			boolean adjusting = true;
//			int iters0 = 1;
//			byte[] b = new byte[size];
//			int run = 0;
//			while (f_run && run < maxruns) {
//				final long start = System.nanoTime();
//				for (int i = 0; i < iters0; i++) {
//					call.func(b);
//				}
//				final long delta = System.nanoTime() - start;
//
//				final long deltaUs = TimeUnit.NANOSECONDS.toMicros(delta);
//				final double throughput = ((double) b.length * iters0) / deltaUs;
//				if (!adjusting) {
//					throughputs[run] = throughput;
//					run++;
//					System.out.format("%-12s | %10d | %13d | %14d |    %16.6f            \r",
//							algorithm, iters0, b.length, delta / iters0, average(throughputs, run));
//				} else {
//					System.out.format("%-12s | %10d | %13d | %14d |    %16.6f [adjusting]\r",
//							algorithm, iters0, b.length, delta / iters0, throughput);
//
//				}
//
//				// adjust iteration to get delta t in the second range (if necessary)
//				if (adjusting) {
//					if ((float) (TimeUnit.NANOSECONDS.toMillis(delta) / 1000.0) < 0.2) {
//						iters0 <<= 1;
//					} else {
//						adjusting = false;
//					}
//				}
//			}
//			size <<= 1;
//			if(f_run){
//				System.out.println();
//			}
//			b = null;
//			System.gc();
//		}
//		System.exit(0);
//	}
//	final double average(double[] throughputs, int n) {
//		double sum = 0.0;
//		for(int i=0; i<n; i++) {
//			sum += throughputs[i];
//		}
//		return sum / (double) n;
//	}
//	interface Call {
//		/**
//		 * func
//		 * @param b
//		 * @return
//		 */
//		byte[] func(final byte[] b);
//	}
//
//	public static Call newCallBlake2b (final int size)  {
//		final Blake2b digest = Blake2b.Digest.newInstance (new Blake2b.Param().setDigestLength(size));
//		return new Call() {
//			@Override final public byte[] func(byte[] b) {
//				digest.reset();
//				digest.update(b, 0, b.length);
//				return digest.digest();
//			}
//		};
//	}
//
//	public static Call newCallJceAlgorithm(final String mdName) {
//		final MessageDigest digest = silentGet (mdName);
//		return new Call() {
//			@Override final public byte[] func(byte[] b) {
//				digest.reset();
//				digest.update(b, 0, b.length);
//				return digest.digest();
//			}
//		};
//	}
//	public static MessageDigest silentGet (final String mdname) {
//		try {
//			return MessageDigest.getInstance(mdname);
//		} catch (Throwable e) {
//			final Error fault = new Error (String.format("Error getting instance of digest <%s>", mdname), e);
//			System.err.printf("%s\n", fault.toString());
//			throw fault;
//		}
//	}
//}
